package com.yeskery.nut.script.function;

import com.yeskery.nut.plugin.NutApplicationSupportBasePlugin;
import com.yeskery.nut.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * 多参数函数基础类
 * @author sprout
 * 2022-05-17 14:37
 */
public abstract class BaseMultiParamFunction extends NutApplicationSupportBasePlugin implements Function {

    /** 日志对象 */
    private final static Logger logger = Logger.getLogger(BaseMultiParamFunction.class.getName());

    /** 分隔符 */
    protected static final String SEPARATOR = ",";

    /** 多参数分隔符 */
    protected static final String MULTI_PARAM_SEPARATOR = "`";

    /** 无参数 */
    private static final int PARAM_SIZE_0 = 0;

    /** 1个参数 */
    private static final int PARAM_SIZE_1 = 1;

    /** 2个参数 */
    private static final int PARAM_SIZE_2 = 2;

    /** 3个参数 */
    private static final int PARAM_SIZE_3 = 3;

    /** 4个参数 */
    private static final int PARAM_SIZE_4 = 4;

    /** 5个参数 */
    private static final int PARAM_SIZE_5 = 5;

    /** 6个参数 */
    private static final int PARAM_SIZE_6 = 6;

    /** 7个参数 */
    private static final int PARAM_SIZE_7 = 7;

    /** 8个参数 */
    private static final int PARAM_SIZE_8 = 8;

    /** 9个参数 */
    private static final int PARAM_SIZE_9 = 9;

    /** 10个参数 */
    private static final int PARAM_SIZE_10 = 10;


    @Override
    public String apply(String content) throws Exception {
        if (content == null || !validParams(content)) {
            return content;
        }
        String[] params = getParams(content);
        try {
            switch (params.length) {
                case PARAM_SIZE_0: return doNoParams(content);
                case PARAM_SIZE_1: return doParams1(content);
                case PARAM_SIZE_2: return doParams2(params, content);
                case PARAM_SIZE_3: return doParams3(params, content);
                case PARAM_SIZE_4: return doParams4(params, content);
                case PARAM_SIZE_5: return doParams5(params, content);
                case PARAM_SIZE_6: return doParams6(params, content);
                case PARAM_SIZE_7: return doParams7(params, content);
                case PARAM_SIZE_8: return doParams8(params, content);
                case PARAM_SIZE_9: return doParams9(params, content);
                case PARAM_SIZE_10: return doParams10(params, content);
                default: return doDefault(params, content);
            }
        } catch (Exception e) {
            logger.info("Function [" + getName() + "] Execute Fail. At Expression: [" + content + "]. " +
                    "Exception Message: [" + e.getClass().getName() + ":" + e.getMessage() + "]");
            return doException(params, content, e);
        }

    }

    /**
     * 参数验证
     * @param content 参数
     * @return 参数是否符合函数要求
     */
    protected boolean validParams(String content) {
        return true;
    }

    /**
     * 处理无参数的函数过程
     * @param param 参数
     * @return 处理结果
     */
    protected String doNoParams(String param) {
        return param;
    }

    /**
     * 处理1个参数的函数过程
     * @param param 参数
     * @return 处理结果
     */
    protected String doParams1(String param) {
        return param;
    }

    /**
     * 处理2个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams2(String[] params, String content) {
        return content;
    }

    /**
     * 处理3个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams3(String[] params, String content) {
        return content;
    }

    /**
     * 处理4个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams4(String[] params, String content) {
        return content;
    }

    /**
     * 处理5个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams5(String[] params, String content) {
        return content;
    }

    /**
     * 处理6个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams6(String[] params, String content) {
        return content;
    }

    /**
     * 处理7个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams7(String[] params, String content) {
        return content;
    }

    /**
     * 处理8个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams8(String[] params, String content) {
        return content;
    }

    /**
     * 处理9个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams9(String[] params, String content) {
        return content;
    }

    /**
     * 处理10个参数的函数过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doParams10(String[] params, String content) {
        return content;
    }

    /**
     * 函数默认处理过程
     * @param params 参数
     * @param content 函数体
     * @return 处理结果
     */
    protected String doDefault(String[] params, String content) {
        return content;
    }

    /**
     * 函数异常处理过程
     * @param params 参数
     * @param content 函数体
     * @param e 异常对象
     * @return 处理结果
     */
    protected String doException(String[] params, String content, Exception e) {
        return content;
    }

    /**
     * 获取参数值数组
     * @param content 参数内容
     * @return 参数值数组
     */
    protected String[] getParams(String content) {
        List<String> collect = Arrays.stream(content.trim().split(SEPARATOR))
                .map(String::trim)
                .filter(s -> !StringUtils.isEmpty(s))
                .collect(Collectors.toList());
        if (collect.size() <= 1) {
            return collect.toArray(new String[0]);
        }
        List<MultiParamMedataIndex> multiParamMedataIndexList = new ArrayList<>();
        int startLineIndex = -1;
        for (int i = 0; i < collect.size(); i++) {
            String line = collect.get(i);
            if (line.startsWith(MULTI_PARAM_SEPARATOR) && !line.endsWith(MULTI_PARAM_SEPARATOR)) {
                startLineIndex = i;
            } else if (!line.startsWith(MULTI_PARAM_SEPARATOR) && line.endsWith(MULTI_PARAM_SEPARATOR)) {
                multiParamMedataIndexList.add(new MultiParamMedataIndex(startLineIndex, i));
            }
        }
        List<String> lines = new ArrayList<>();
        for (int i = 0; i < collect.size(); i++) {
            final int start = i;
            Optional<MultiParamMedataIndex> optional = multiParamMedataIndexList.stream().filter(m -> m.startIndex == start).findFirst();
            if (optional.isPresent()) {
                MultiParamMedataIndex multiParamMedataIndex = optional.get();
                StringBuilder line = new StringBuilder();
                for (int j = multiParamMedataIndex.startIndex; j <= multiParamMedataIndex.endIndex; j++) {
                    if (j == multiParamMedataIndex.startIndex) {
                        line.append(collect.get(j).substring(1)).append(SEPARATOR);
                    } else if (j == multiParamMedataIndex.endIndex) {
                        String str = collect.get(j);
                        line.append(str, 0, str.length() - 1);
                    } else {
                        line.append(collect.get(j)).append(SEPARATOR);
                    }
                }
                lines.add(line.toString());
                i = multiParamMedataIndex.endIndex;
            } else {
                String lineStr = collect.get(i);
                if (lineStr.startsWith(MULTI_PARAM_SEPARATOR) && lineStr.endsWith(MULTI_PARAM_SEPARATOR)) {
                    lines.add(lineStr.substring(1, lineStr.length() - 1));
                } else {
                    lines.add(lineStr);
                }
            }
        }
        return lines.toArray(new String[0]);
    }

    /**
     * 多参数元数据索引对象
     * @author sprout
     * 2022-07-19 14:59
     */
    private static class MultiParamMedataIndex {
        /** 开始索引 */
        private final int startIndex;
        /** 结束索引 */
        private final int endIndex;

        /**
         * 构建多参数元数据索引对象
         * @param startIndex 开始索引
         * @param endIndex 结束索引
         */
        private MultiParamMedataIndex(int startIndex, int endIndex) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }
    }
}
